use crate::sys_log;
use log::{max_level, set_logger, Level, LevelFilter, Log, Metadata, Record};

struct ConsoleLog {}

impl ConsoleLog {
    pub fn new() -> Self {
        Self {}
    }
}

pub fn from_level_for_u8(value: Level) -> u8 {
    match value {
        Level::Trace => sys_log::LOG_LEVEL_OFF,
        Level::Debug => sys_log::LOG_LEVEL_DEBUG,
        Level::Info => sys_log::LOG_LEVEL_INFO,
        Level::Warn => sys_log::LOG_LEVEL_WARN,
        Level::Error => sys_log::LOG_LEVEL_ERROR,
    }
}

pub fn from_u8_for_level_filter(value: u8) -> LevelFilter {
    match value {
        sys_log::LOG_LEVEL_DEBUG => LevelFilter::Debug,
        sys_log::LOG_LEVEL_INFO => LevelFilter::Info,
        sys_log::LOG_LEVEL_WARN => LevelFilter::Warn,
        sys_log::LOG_LEVEL_ERROR => LevelFilter::Error,
        sys_log::LOG_LEVEL_PASS => LevelFilter::Info,
        sys_log::LOG_LEVEL_OFF => LevelFilter::Off,
        _ => LevelFilter::Info,
    }
}

pub fn from_level_filter_for_u8(value: LevelFilter) -> u8 {
    match value {
        LevelFilter::Trace => sys_log::LOG_LEVEL_DEBUG,
        LevelFilter::Debug => sys_log::LOG_LEVEL_DEBUG,
        LevelFilter::Info => sys_log::LOG_LEVEL_INFO,
        LevelFilter::Warn => sys_log::LOG_LEVEL_WARN,
        LevelFilter::Error => sys_log::LOG_LEVEL_ERROR,
        LevelFilter::Off => sys_log::LOG_LEVEL_OFF,
    }
}

impl Log for ConsoleLog {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        let l = from_level_for_u8(metadata.level());
        sys_log::set_log_level(l);
        sys_log::get_log_level() != sys_log::LOG_LEVEL_OFF
    }

    fn log(&self, record: &Record<'_>) {
        let lf = from_level_filter_for_u8(max_level());
        if sys_log::get_log_level() != lf {
            sys_log::set_log_level(lf);
        }
        let l = from_level_for_u8(record.level());
        if l >= lf {
            sys_log::write_log(
                l,
                record.module_path().unwrap_or(""),
                record.line().unwrap_or(0),
                record.args().clone(), //@TODO optimize
                true,
            );
        }
    }
    fn flush(&self) {}
}

static CONSOLE_LOG: ConsoleLog = ConsoleLog {};

pub fn init_console_logger() {
    unsafe {
        sys_log::detect_env_log_level();
    }
    let _ = set_logger(&CONSOLE_LOG);
}
